package com.henry.utils;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * Redisson封装
 * @author hanLin.liu
 * @create 2024-11-19 15:43
 */
@Slf4j
@AllArgsConstructor
public class RedissonUtil {

    private final RedissonClient redissonClient;


    /** 锁前缀 */
    private static final String LHL_LOCK = "LHL-LOCK";

    /** 默认等待锁时间 */
    private static final long DEFAULT_WAIT_TIME = 1L;

    /** 默认释放锁时间 */
    private static final long DEFAULT_LEASE_TIME = 60L;

    /** 默认时间单位 */
    private final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;

    /**
     * @param keyLock 加锁的key
     * @return 是否加锁成功
     */
    public boolean lock(String keyLock){
        return lock(keyLock, DEFAULT_WAIT_TIME, DEFAULT_LEASE_TIME, DEFAULT_TIME_UNIT);
    }

    /**
     * 加锁-自定义策略
     * @param keyLock 加锁的key
     * @param waitTime 加锁等待时间
     * @param leaseTime 锁释放时间
     * @param timeUnit 时间单位
     * @return 是否加锁成功
     */
    public boolean lock(String keyLock, long waitTime, long leaseTime, TimeUnit timeUnit){

        if(redissonClient == null){
            log.error("不支持锁定操作，redissonClient 为 null！");
            return false;
        }
        String lockName = LHL_LOCK + "-" + keyLock;
        RLock lock = redissonClient.getLock(lockName);
        try {
            // 尝试加锁，等待waitTime后还没加到锁就返回false，加锁成功后leaseTime后释放
            if(!lock.tryLock(waitTime, leaseTime, timeUnit)){
                log.info("线程{}==>,【{}】获取锁失败！", lockName, Thread.currentThread().getName());
                return false;
            }
            log.info("线程{}==>,【{}】获取锁成功！", lockName, Thread.currentThread().getName());
        } catch (InterruptedException e) {
            log.error("获取锁异常！key = 【{}】 errorMsg = 【{}】", lockName, e);
            lock.unlock();
            return false;
        }
        return true;
    }

    /**
     * 解锁
     * @param keyLock 解锁的key
     * @return
     */
    public boolean unlock(String keyLock){
        if(redissonClient == null){
            log.error("redissonClient 为 null！");
            return false;
        }
        String lockName = LHL_LOCK + "-" + keyLock;
        RLock lock = redissonClient.getLock(lockName);
        lock.unlock();
        log.info("线程{}==>,【{}】解锁成功！", lockName ,Thread.currentThread().getName());
        return true;
    }

    /**
     * 设置一个 String 类型元素
     * @param key 键
     * @param value 值
     */
    public void addValueString(String key, String value){
        addValueString(key, value, DEFAULT_LEASE_TIME, TimeUnit.SECONDS);
    }

    /**
     * 设置一个 String 类型元素
     * @param key 键
     * @param value 值
     * @param time 过期时间
     * @param timeUnit 时间单位
     */
    public void addValueString(String key, String value, Long time, TimeUnit timeUnit){
        redissonClient.getBucket(key).set(value, time, timeUnit);
    }

    /**
     * 获取一个 String 类型元素
     * @param key
     * @return
     */
    public String getValueString(String key){
        return redissonClient.<String>getBucket(key).get();
    }


    /**
     * 添加一个zSet元素
     * @param key
     * @param value
     * @param source
     * @param expire
     */
    public void addZSetSingle(String key, Object value, double source, long expire){
        RScoredSortedSet<Object> sortedSet = redissonClient.getScoredSortedSet(key);
        sortedSet.addScore(value, source);
        sortedSet.expire(Duration.ofSeconds(expire));
    }

    /**
     * 获取key对应的ZSet
     * @param key
     * @return
     */
    public RScoredSortedSet<Object> getZSetByKey(String key){
        return redissonClient.getScoredSortedSet(key);
    }

    /**
     * 对应ZSet集合进行操作
     */
    class ZSetNode{
        private double source;
        private Object value;
    }

}
